﻿/**
<code>
  <author name="Zealic" email="zealic(at)gmail.com" type="Creator"/>
</code>
**/
using System;
using System.Collections;

namespace Zealib.Numeric
{
    public struct BigDecimal
    {
        #region Fields
        private BigInteger _Integer;
        private uint[] m_FractionData;
        private int _Precision;

        #endregion

        #region Constuctor
        public BigDecimal(int value)
        {
            _Integer = new BigInteger(value);
            m_FractionData = new uint[0];
            _Precision = -1;
        }

        public BigDecimal(uint value)
        {
            _Integer = new BigInteger(value);
            m_FractionData = new uint[0];
            _Precision = -1;
        }

        public BigDecimal(long value)
        {
            _Integer = new BigInteger(value);
            m_FractionData = new uint[0];
            _Precision = -1;
        }


        public BigDecimal(ulong value)
        {
            _Integer = new BigInteger(value);
            m_FractionData = new uint[0];
            _Precision = -1;
        }

        public BigDecimal(float value)
            : this((double)value)
        {
        }

        public BigDecimal(double value)
            : this((decimal)value)
        {
        }

        public BigDecimal(decimal value)
        {
            _Integer = new BigInteger(value);
            var strValue = value.ToString();
            m_FractionData = ExtractFraction(strValue);
            _Precision = -1;
        }

        internal BigDecimal(short sign, uint[] leftData, uint[] rightData)
        {
            _Integer = new BigInteger(sign, leftData);
            m_FractionData = new uint[leftData.Length];
            Buffer.BlockCopy(rightData, 0, m_FractionData, 0, m_FractionData.Length * 4);
            _Precision = -1;
        }

        #endregion

        #region Helper
        private static uint[] ExtractFraction(string value)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Public members
        #region Operator
        public static BigDecimal operator +(BigDecimal value)
        {
            return value;
        }

        public static BigDecimal operator -(BigDecimal value)
        {
            return Negate(value);
        }

        public static BigDecimal operator +(BigDecimal x, BigDecimal y)
        {
            return Add(x, y);
        }

        public static BigDecimal operator -(BigDecimal x, BigDecimal y)
        {
            return Subtract(x, y);
        }

        public static BigDecimal operator *(BigDecimal x, BigDecimal y)
        {
            return Multiply(x, y);
        }

        public static BigDecimal operator /(BigDecimal x, BigDecimal y)
        {
            return Divide(x, y);
        }

        public static BigDecimal operator %(BigDecimal x, BigDecimal y)
        {
            BigDecimal result;
            DivRem(x, y, out result);
            return result;
        }

        public static bool operator >(BigDecimal x, BigDecimal y)
        {
            return GreaterThan(x, y);
        }

        public static bool operator <(BigDecimal x, BigDecimal y)
        {
            return LessThan(x, y);
        }

        public static bool operator >=(BigDecimal x, BigDecimal y)
        {
            return GreaterThanOrEqual(x, y);
        }

        public static bool operator <=(BigDecimal x, BigDecimal y)
        {
            return LessThanOrEqual(x, y);
        }

        public static bool operator ==(BigDecimal x, BigDecimal y)
        {
            return Equals(x, y);
        }

        public static bool operator !=(BigDecimal x, BigDecimal y)
        {
            return !Equals(x, y);
        }

        public static implicit operator BigDecimal(byte value)
        {
            return new BigDecimal((int)value);
        }

        public static implicit operator BigDecimal(sbyte value)
        {
            return new BigDecimal((uint)value);
        }

        public static implicit operator BigDecimal(short value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(ushort value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(int value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(uint value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(long value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(ulong value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(float value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(double value)
        {
            return new BigDecimal(value);
        }

        public static implicit operator BigDecimal(decimal value)
        {
            return new BigDecimal(value);
        }
        #endregion

        #region Function implement
        public static BigDecimal Abs(BigDecimal value)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal Add(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal Subtract(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal Multiply(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal Divide(BigDecimal dividend, BigDecimal divisor)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal DivRem(BigDecimal dividend, BigDecimal divisor, out BigDecimal remainder)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal Remainder(BigDecimal dividend, BigDecimal divisor)
        {
            BigDecimal result;
            DivRem(dividend, divisor, out result);
            return result;
        }

        public static BigDecimal Pow(BigDecimal baseValue, BigDecimal exponent)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal ModPow(BigDecimal baseValue, BigDecimal exponent, BigDecimal modulus)
        {
            throw new NotImplementedException();
        }

        public static BigDecimal Negate(BigDecimal value)
        {
            return new BigDecimal();
        }


        public static bool LessThan(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public static bool LessThanOrEqual(BigDecimal x, BigDecimal y)
        {
            return (LessThan(x, y) || Equals(x, y));
        }

        public static bool GreaterThan(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public static bool GreaterThanOrEqual(BigDecimal x, BigDecimal y)
        {
            return (GreaterThan(x, y) || Equals(x, y));
        }

        public static bool Equals(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public static int Compare(BigDecimal x, BigDecimal y)
        {
            throw new NotImplementedException();
        }

        public int CompareTo(BigDecimal other)
        {
            return Compare(this, other);
        }

        #endregion

        public static BigDecimal Parse(string strValue)
        {
            BigDecimal ret;
            if (!TryParse(strValue, out ret))
            {
                throw new FormatException(strValue);

            }
            return ret;
        }

        public static bool TryParse(string strValue, out BigDecimal result)
        {
            throw new NotImplementedException();
        }


        public byte[] ToByteArray()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Override
        public override bool Equals(object obj)
        {
            throw new NotImplementedException();
        }

        public override int GetHashCode()
        {
            if (_Integer.Sign == 0) return 0;
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Properties
        public BigInteger Integer
        {
            get { return _Integer; }
        }

        public int Length
        {
            get
            {
                int len;
                len = m_FractionData == null ? 0 : m_FractionData.Length;
                return _Integer.Length + len;
            }
        }

        public int Precision
        {
            get
            {
                return _Precision;
            }
            set
            {
                if (value < -1) throw new ArgumentOutOfRangeException("value");
                _Precision = value;
            }
        }

        #endregion

    }
}
